package org.wattdepot.cli;

import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.resource.source.jaxb.Source;
import org.wattdepot.resource.source.jaxb.SourceIndex;
import org.wattdepot.resource.source.jaxb.SourceRef;
import org.wattdepot.util.tstamp.Tstamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.resource.property.jaxb.Properties;

/**
 * A simple command line interface to WattDepot that shows basic connection and processing. Modified
 * from Philip Johnson's CommandLineInterface.
 * 
 * @author Scott Wong and Kelli Sawai
 * 
 */
public class CommandLineInterface {
  /** The URL to the public WattDepot Server. */
  private String hostUri = "http://server.wattdepot.org:8182/wattdepot/";
  /** Holds an instance of the WattDepot client. */
  protected WattDepotClient client;

  /** Explains the error. */
  public static final String resourceMessage = "Error: Resource not found";
  /** Explains the error. */
  public static final String futureTimestampMessage =
      "Error: Timestamp cannot be in the future";
  /** Explains the error. */
  public static final String badTimestampMessage = "Error: Resource not found";
  /** Explains the error. */
  public static final String badXmlMessage = "Error: Bad XML";
  /** Explains the error. */
  public static final String notAuthorizedMessage =
      "Error: Not authorized to access the requested resource ";

  /** Space. */
  protected String cm = ",";

  /** New Line. */
  protected String nl = "\n";

  /** Tab. */
  protected String tb = "\t";

  /**
   * Connect to the service and execute some simple commands.
   */
  public CommandLineInterface() {
    client = new WattDepotClient(this.hostUri);
  }
  
  /**
   * Converts string to a timestamp of type XMLGregorianCalendar.
   * 
   * @param time Time
   * @return timestamp XMLGregorianCalendar
   */
  protected XMLGregorianCalendar toTimestamp(String time) {
    XMLGregorianCalendar timestamp = null;
    try {
      timestamp = Tstamp.makeTimestamp(time);
    }
    catch (Exception e) {
      System.out.println("should never happen.");
    }
    return timestamp;
  }

  /**
   * Formats properties by removing unnecessary brackets and words.
   * 
   * @param properties2 to be formated
   * @return String of properly formated properties
   */
  protected String formatProperties(Properties properties2) {
    String properties = properties2.toString();
    properties = properties.replace("Property [key=", "(");
    properties = properties.replace("value=", "");
    properties = properties.replace("]]", ")");
    properties = properties.replace("[", "");
    properties = properties.replace(",", " :");
    properties = properties.replace("] :", "),");

    return properties;
  }

  /**
   * Returns a string containing a list of all public sources available on this server.
   * 
   * @return A list of sources as a string.
   * @throws WattDepotClientException If problems occur obtaining the list of sources.
   */
  public String getSourcesInfo() throws WattDepotClientException {
    StringBuffer buff = new StringBuffer(20);
    buff.append("All public sources:").append(cm);
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      buff.append(source.getName()).append(cm);
    }
    return buff.toString();
  }

  /**
   * Returns a sample Source. It's the first one returned by the WattDepot server in its index of
   * sources.
   * 
   * @return The sample Source.
   * @throws WattDepotClientException If problems occur getting the source index.
   */
  public Source getSampleSource() throws WattDepotClientException {
    SourceIndex index = client.getSourceIndex();
    SourceRef ref = index.getSourceRef().get(0);
    return client.getSource(ref);
  }

  /**
   * Returns a double indicating the current power generated by a sample source on November 1, 2009.
   * 
   * @param source The source we want the current power from.
   * @return A double indicating power generated.
   * @throws WattDepotClientException If problems occur obtaining the power value.
   */
  public double getPowerGenerated(Source source) throws WattDepotClientException {
    XMLGregorianCalendar now = null;
    try {
      now = Tstamp.makeTimestamp("2009-11-01");
    }
    catch (Exception e) {
      System.out.println("should never happen.");
    }
    return client.getPowerGenerated(source.getName(), now);
  }

  /**
   * The main program that is invoked from 'java -jar wattdepot-cli.jar'.
   * 
   * @param args All args are ignored.
   * @throws WattDepotClientException If anything goes wrong.
   */
  public static void main(String[] args) throws WattDepotClientException {
    String userInput;
    Scanner input = new Scanner(System.in);
    WattDepotCliCommand command = null;
    Map<String, WattDepotCliCommand> commandMap =
        new HashMap<String, WattDepotCliCommand>();

    // Adds entries to the command map.
    commandMap.put("help", new HelpCommand());
    commandMap.put("listsrc", new ListSources());
    commandMap.put("summary", new SrcSummary());
    commandMap.put("sensordata", new SensorInfo());
    commandMap.put("dailydata", new DaySensorData());
    commandMap.put("power", new ListPowerTime());
    commandMap.put("powerstats", new PowerStats());
    commandMap.put("total", new ListTotalDay());
    commandMap.put("chart", new ChartCommand());
    commandMap.put("fuel", new FuelType());
    commandMap.put("Tpower", new TotalPower());
    commandMap.put("carbon", new CarbonData());

    CommandLineInterface cli = new CommandLineInterface();
    // Stop right away if we cannot contact server.
    if (!cli.client.isHealthy()) {
      System.out.println("Failed to connect to " + cli.client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    System.out.println("Connected to " + cli.client.getWattDepotUri());

    while (true) {
      System.out.print(">");
      // Store users input.
      userInput = input.nextLine();

      // if the user doesn't enter a command.
      if (userInput.isEmpty()) {
        System.out.println("Please enter a command.");
      }

      // if the user chooses to quit.
      if (userInput.compareToIgnoreCase("quit") == 0) {
        System.out.println("Exited the system");
        System.exit(0);
      }

      // if the user chooses the help command.
      if (userInput.compareToIgnoreCase("help") == 0) {
        command = commandMap.get("help");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the sources command.
      if (userInput.matches("sources")) {
        command = commandMap.get("listsrc");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the summary of a souce command.
      if (userInput.matches("summary\\s.*")) {
        command = commandMap.get("summary");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the sensordata command.
      if (userInput.matches("sensordata\\s.*")) {
        command = commandMap.get("sensordata");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the dailysensordata command.
      if (userInput.matches("dailysensordata\\s.*")) {
        command = commandMap.get("dailydata");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the power source command.
      if (userInput.matches("power\\s.*")) {
        command = commandMap.get("power");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the powerstats command.
      if (userInput.matches("powerstats\\s.*")) {
        command = commandMap.get("powerstats");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the total carbon/energy command.
      if (userInput.matches("total\\s.*")) {
        command = commandMap.get("total");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the chart command.
      if (userInput.matches("chart\\s.*")) {
        command = commandMap.get("chart");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the fueltypes command.
      if (userInput.matches("fueltypes\\s.*")) {
        command = commandMap.get("fuel");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the fueltypes command.
      if (userInput.matches("totalpower\\s.*")) {
        command = commandMap.get("Tpower");
        System.out.println(command.doCommand(userInput));
      }

      // if the user chooses the fueltypes command.
      if (userInput.matches("carboncontent\\s.*")) {
        command = commandMap.get("carbon");
        System.out.println(command.doCommand(userInput));
      }
    }
  }
}
